package tk.hongbo.stream

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.util.Size
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import okhttp3.*
import okio.ByteString
import okio.ByteString.Companion.toByteString
import tk.hongbo.stream.coder.AvcEncoder
import tk.hongbo.stream.coder.ImageHelper
import tk.hongbo.stream.coder.YUV.getMediaCodecData
import tk.hongbo.stream.databinding.ActivityMainBinding
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit


const val TAG = "Chat-client"

class MainActivity : AppCompatActivity(), ImageAnalysis.Analyzer {

    private lateinit var binding: ActivityMainBinding
    private val Context.setDataStore by preferencesDataStore("setting")
    private val IP_KEY = stringPreferencesKey("ip")
    private var socket: WebSocket? = null
    private var encoder: AvcEncoder? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val ipFlow: Flow<String> = setDataStore.data.map {
            it[IP_KEY] ?: ""
        }
        GlobalScope.launch(Dispatchers.IO) {
            ipFlow.collect {
                var realUrl = "ws://192.168.15.76:9898"
                if (it.isNotEmpty()) {
                    realUrl = "ws://${it}:9898"
                }
                start(realUrl)
            }
        }

        //切换摄像头
        binding.button2.setOnClickListener { switch() }
        //拍照
        binding.button3.setOnClickListener { takePicture() }
        //录像
        //binding.button4.setOnClickListener { takeVideo() }

        binding.button.setOnClickListener { reConnect() }
        //Camera Preview
        initCamera()
    }

    private fun start(url: String) {
        socket?.close(1000, "Retry Connecting")
        //设置Okhttp
        val client = OkHttpClient.Builder().readTimeout(3, TimeUnit.SECONDS)
            .writeTimeout(3, TimeUnit.SECONDS).connectTimeout(3, TimeUnit.SECONDS)
            .build()

        //使用Url，构建WebSocket请求
        val request = Request.Builder().get().url(url).build()

        //发起连接，配置回调
        client.newWebSocket(request, object : WebSocketListener() {
            override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                super.onClosed(webSocket, code, reason)
                Log.d(TAG, "连接关闭,Code:${code},reason:${reason}")
            }

            override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
                super.onClosing(webSocket, code, reason)
                Log.d(TAG, "连接关闭中,Code:${code},reason:${reason}")
            }

            override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                super.onFailure(webSocket, t, response)
                Log.d(TAG, "连接失败,${t.message}")
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                super.onMessage(webSocket, text)
                Log.d(TAG, "收到消息文本:${text}")
            }

            override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                super.onMessage(webSocket, bytes)
                Log.d(TAG, "收到消息二进制:${bytes}")
            }

            override fun onOpen(webSocket: WebSocket, response: Response) {
                super.onOpen(webSocket, response)
                socket = webSocket
                Log.d(TAG, "连接成功...")
            }
        })
    }

    private var cameraLensFacing: Int = CameraSelector.LENS_FACING_BACK
    private lateinit var imageCapture: ImageCapture
    private lateinit var videoCapture: VideoCapture
    private lateinit var imageAnalysis: ImageAnalysis

    /**
     * 相机初始化
     */
    private fun initCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener({
            bindPreview(cameraProviderFuture.get())
        }, ContextCompat.getMainExecutor(this))
    }

    @SuppressLint("RestrictedApi")
    private fun bindPreview(cameraProvider: ProcessCameraProvider) {
        val cameraSelector: CameraSelector = CameraSelector.Builder()
            .requireLensFacing(cameraLensFacing).build()

        imageCapture = ImageCapture.Builder().build()

        videoCapture = VideoCapture.Builder().build()

        //分析
        imageAnalysis = ImageAnalysis.Builder()
            .setTargetResolution(Size(1280, 960))
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .build()
        imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), this)

        val preview = Preview.Builder().build()
        preview.setSurfaceProvider(binding.surfaceView.surfaceProvider)

        cameraProvider.unbindAll()
        cameraProvider.bindToLifecycle(
            this, cameraSelector, imageCapture, imageAnalysis, preview
        )
    }

    private fun switch() {
        cameraLensFacing = if (cameraLensFacing == CameraSelector.LENS_FACING_BACK) {
            CameraSelector.LENS_FACING_FRONT
        } else {
            CameraSelector.LENS_FACING_BACK
        }
        initCamera()
    }

    private fun takePicture() {
        imageCapture.takePicture(ContextCompat.getMainExecutor(this), object :
            ImageCapture.OnImageCapturedCallback() {
            override fun onCaptureSuccess(image: ImageProxy) {
                val bitmap = ImageHelper.getBitmap(image)
                runOnUiThread {
                    binding.imageView.setImageBitmap(bitmap)
                }
            }

            override fun onError(exception: ImageCaptureException) {
                Log.e(TAG, "takePicture", exception)
            }
        })
    }

    @SuppressLint("RestrictedApi")
    private fun takeVideo() {
        if (binding.button4.text.equals("停止")) {
            binding.button4.text = "录像"
            videoCapture.stopRecording()
        } else {
            val file = File(
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).path + "/CameraX" + SimpleDateFormat(
                    "yyyyMMddHHmmss", Locale.CHINA
                ).format(System.currentTimeMillis()) + ".mp4"
            )
            val option = VideoCapture.OutputFileOptions.Builder(file).build()
            if (ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.RECORD_AUDIO
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                return
            }
            videoCapture.startRecording(option, Executors.newSingleThreadExecutor(), object :
                VideoCapture.OnVideoSavedCallback {
                override fun onVideoSaved(outputFileResults: VideoCapture.OutputFileResults) {
                    Log.d(TAG, "视频录制成功")
                }

                override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
                    Log.e(TAG, "视频录制出错", cause)
                }
            })
            binding.button4.text = "停止"
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        encoder?.StopThread()
    }

    override fun analyze(image: ImageProxy) {
        if (encoder == null) {
            //编码器监听
            encoder = AvcEncoder(image.width, image.height, 30) {
                socket?.send(it.toByteString())
            }
        }
        encoder?.StartEncoderThread(getMediaCodecData(image))
    }

    /**
     * 重新设置服务连接
     */
    private fun reConnect() {
        val edit = EditText(this)
        AlertDialog.Builder(this).setTitle("服务IP").setMessage("设置确认后需要重启生效")
            .setView(edit).setNegativeButton("取消", null)
            .setPositiveButton(
                "确定"
            ) { p0, p1 ->
                GlobalScope.launch {
                    saveIp(edit.text.trim().toString())
                }
            }.show()
    }

    private suspend fun saveIp(ip: String) {
        setDataStore.edit {
            it[IP_KEY] = ip
        }
    }
}